package com.xxmw.transaction.common.utils.bourse;

import com.alibaba.fastjson.JSONObject;
import com.xxmw.transaction.common.utils.Assert;
import com.xxmw.transaction.common.utils.HmacUtil;
import com.xxmw.transaction.common.utils.http.HttpClientUtil;
import com.xxmw.transaction.common.utils.http.HttpHeader;
import com.xxmw.transaction.enumeration.BourseEnum;
import com.xxmw.transaction.enumeration.TradeTypeEnum;
import com.xxmw.transaction.model.app.BourseApi;
import com.xxmw.transaction.model.app.BourseOrder;
import com.xxmw.transaction.model.brick.BrickOrder;
import com.xxmw.transaction.vo.BalanceVo;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.*;

/**
 * P网工具类
 * @author luowenliang
 * @since 2020/3/30 15:54
 */
@Slf4j
public class PoloniexUtil {

    /**
     * 私有接口特定参数
     */
    private static final String BASE_URL = "https://poloniex.com/tradingApi";

    /**
     * 获取余额指令
     */
    private static final String BALANCES_COMMAND = "returnBalances";

    /**
     * 订单状态查询指令
     */
    private static final String ORDER_STATUS_COMMAND = "returnOrderStatus";



    /**
     * 卖指令
     */
    private static final String SELL_COMMAND = "sell";

    /**
     * 购买指令
     */
    private static final String BUY_COMMAND = "buy";

    /**
     * 取消订单指令
     */
    private static final String CANCEL_ORDER_COMMAND = "cancelOrder";



    public static Map<String, Object> getSymbolInfo (String symbol) {
        Map<String, Object> map = new HashMap<>(16);
        switch (symbol) {
            case "btcusdt":
                map.put("symbol", "USDT_BTC");
                map.put("id", 121);
                break;
            case "ethusdt":
                map.put("symbol", "USDT_ETH");
                map.put("id", 149);
                break;
            case "USDT_BTC":
                map.put("symbol", "btcusdt");
                map.put("id", 121);
                break;
            case "USDT_ETH":
                map.put("symbol", "ethusdt");
                map.put("id", 149);
                break;
            default:
        }
        return map;
    }

    public static Map<String, Object> getSymbol (int symbolId) {
        Map<String, Object> map = new HashMap<>(16);
        switch (symbolId) {
            case 121:
                map.put("outSymbol", "USDT_BTC");
                map.put("symbol", "btcusdt");
                break;
            case 149:
                map.put("outSymbol", "USDT_ETH");
                map.put("symbol", "ethusdt");
                break;
            default:
        }
        return map;
    }

    public static BalanceVo getBalance(BourseApi api, String currency) {
        JSONObject balances = getBalances(api);
        BigDecimal available = balances.getBigDecimal(currency.toUpperCase());
        BalanceVo balanceVo = new BalanceVo();
        balanceVo.setAvailable(available);

        return balanceVo;
    }

    /**
     * 获取余额
     * @param api
     * @param currencys
     * @return
     */
    public static Map<String, BalanceVo> getBalance(BourseApi api, List<String> currencys) {

        Map<String, BalanceVo> map = new HashMap<>(16);
        if (currencys.size() <= 0) {
            return map;
        }
        JSONObject balances = getBalances(api);
        if (Assert.isNullOrEmpty(balances)) {
            return map;
        }
        for (String currency : currencys) {
            // P网只有获取余额没有冻结数据
            BalanceVo balanceVo = new BalanceVo();
            BigDecimal available = balances.getBigDecimal(currency.toUpperCase());
            balanceVo.setAvailable(available);
            balanceVo.setTotal(available);

            log.info("p网获取{}余额信息：{}", currency, balanceVo.toString());
            map.put(currency, balanceVo);
        }
        return map;
    }

    /**
     * 下单接口
     * @param api
     * @param order
     * @return
     */
    public static void order (BourseApi api, BourseOrder order) {
        Map<String, String> map = new LinkedHashMap<>();
        // 执行指令
        if (order.getTradeType().equals(TradeTypeEnum.BUY_MARKET.getValue())
                || order.getTradeType().equals(TradeTypeEnum.BUY_LIMIT.getValue())) {
            map.put("command", BUY_COMMAND);
        } else {
            map.put("command", SELL_COMMAND);
        }
        // 无市价单  手动操作
        //如果类型是市价买  金额上浮  市价卖 金额下浮
        if (order.getTradeType().equals(TradeTypeEnum.BUY_MARKET.getValue())) {
            BigDecimal price = order.getPrice().multiply(new BigDecimal("1.01"));
            order.setPrice(price);
            order.setTotalPrice(price.multiply(order.getNum()));
        } else if (order.getTradeType().equals(TradeTypeEnum.SELL_MARKET.getValue())) {
            BigDecimal price = order.getPrice().multiply(new BigDecimal("0.99"));
            order.setPrice(price);
            order.setTotalPrice(price.multiply(order.getNum()));
        }

        // 交易对获取
        String symbol = BourseEnum.POLONIEX.getSymbolFormat().symbolFormat(order.getBaseCurrency(), order.getQuoteCurrency());
        map.put("currencyPair", symbol);

        map.put("rate", order.getNum().toPlainString());
        map.put("amount", order.getPrice().toPlainString());
        map.put("clientOrderId", String.valueOf(order.getId()));

        String response = poloniexPost(map, api);
        log.info("p网下单返回数据：{}", response);
        JSONObject object = JSONObject.parseObject(response);
        if (Assert.isNotNullOrEmpty(object) && Assert.isNotNullOrEmpty(object.getString("orderNumber"))) {
            order.setFee(object.getBigDecimal("fee"));
            order.setOutId(object.getString("orderNumber"));
            order.setStatus(BourseOrder.Status.PUBLISHED.value());
        } else {
            order.setStatus(BourseOrder.Status.PUBLISH_ERROR.value());
            log.error("下单失败： {}", response);
        }
    }

    /**
     * P网统一请求方法
     * @param map
     * @return
     */
    private static String poloniexPost (Map<String, String> map, BourseApi api) {
        // 随机字符串
        String nonce = String.valueOf(System.currentTimeMillis());
        map.put("nonce", nonce);
        StringBuilder params = new StringBuilder();
        map.entrySet().forEach(entry -> params.append(entry.toString()).append("&"));
        String paramStr = params.substring(0, params.length() - 1);
        String sign = HmacUtil.poloniexSign(paramStr, api.getSecretKey());

        HttpHeader headers = new HttpHeader();
        headers.add("Key", api.getAccessKey());
        headers.add("Sign", sign);
        String res = HttpClientUtil.postByBody(BASE_URL, headers, map);
        return res;
    }

    /**
     * 获取该账号所有余额信息
     * @param api
     * @return
     */
    private static JSONObject getBalances (BourseApi api) {
        Map<String, String> map = new TreeMap<>();
        map.put("command", BALANCES_COMMAND);
        String res = poloniexPost(map, api);
        JSONObject response = JSONObject.parseObject(res);
        return response;
    }

    public static void main(String[] args) {
        // 创建api
        BourseApi api = new BourseApi();
        api.setAccessKey("SMVSGBAR-YLWSS099-2SHG78NC-M2IWSSOB");
        api.setSecretKey("850838fdd6f620f761da2e2e7dbb02870a8ae595aed817fd35172cb581b6ac3ac0f4d2e3a1d641008ec868a041869e3b0d382912c556d1017c449f2135efd890");

        // getBalance(api, "usdt");
        // 创建订单
        BrickOrder order = new BrickOrder();
        order.setTradeType(TradeTypeEnum.BUY_MARKET.getValue());
        order.setNum(BigDecimal.ONE);
        order.setId(123L);
        order.setBaseCurrency("btc");
        order.setQuoteCurrency("usdt");
        order.setPrice(new BigDecimal("11220"));
        order.setOutId("123");
        orderInfo(api, order);

    }


    public static void orderInfo(BourseApi api, BrickOrder order) {
        // TODO 等待测试
        Map<String, String> map = new LinkedHashMap<>();
        map.put("command", ORDER_STATUS_COMMAND);
        map.put("orderNumber", order.getOutId());
        String s = poloniexPost(map, api);
        JSONObject object = JSONObject.parseObject(s);
        if (Assert.isNotNullOrEmpty(object) && Assert.isNotNullOrEmpty(object.getBoolean("success")) && object.getBoolean("success")) {
            String status = object.getJSONObject("6071071").getString("status");
            if (!status.equals("Open")) {
                order.setStatus(BourseOrder.Status.DEALED.value());
                order.setDealTime(object.getJSONObject("6071071").getDate("date"));
            }
        }
    }

    /**
     * 取消订单
     * @param api
     * @param order
     * @return
     */
    public static boolean cancelOrder (BourseApi api, BourseOrder order) {
        Map<String, String> map = new LinkedHashMap<>();
        map.put("command", CANCEL_ORDER_COMMAND);
        map.put("orderNumber", order.getOutId());
        String s = poloniexPost(map, api);
        JSONObject object = JSONObject.parseObject(s);
        return object.getBoolean("success");
    }
}
